﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Linq;
using EnvDTE;
using EnvDTE80;
using System.ComponentModel;
using System.Reflection;
using System.Drawing.Design;
using SPVisualDev.VSAddin.Dialogs;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using SPVisualDev.VSAddin.Dialogs.PropertySheets;

namespace SPVisualDev.VSAddin
{
    internal class FeatureManager
    {
        private ProjectItem m_feature_folder;
        private SpecialProject m_special_project;

        private XmlDocument m_feature_file;
        private int m_feature_file_init_xml_hash_code;

        private List<ElementInfo> m_elements_list;
        private Dictionary<string, XmlDocument> m_element_files_list;
        private Dictionary<string, int> m_elements_init_xml_hash_code;

        private Dictionary<string, List<CodeClass>> m_classes;
        private int m_classes_init_hash;
        private bool m_has_classes;

        private string m_assembly_name;
        private int m_element_counter;
        private Guid m_feature_id;

        private List<Guid> m_activation_dep_list = new List<Guid>();


        public FeatureManager(SpecialProject project, ProjectItem FeatureFolder)
        {
            m_feature_folder = FeatureFolder;
            m_special_project = project;

            Init();
        }

        public string FeatureID { get; set; }
        public string FeatureTitle { get; set; }
        public string FeatureDescription { get; set; }
        public string FeatureVersion { get; set; }
        public string FeatureScope { get; set; }
        public string FeatureDefaultResourceFile { get; set; }
        public string FeatureDefaultCodeFolder { get; set; }
        public string FeatureDefaultCodeNamespace { get; set; }
        public bool? FeatureHidden { get; set; }
        public string FeatureEventReceiverAssembly { get; set; }
        public string FeatureEventReceiverClass { get; set; }

        public string AssemblyStrongName { get { RefreshAssemblyName(); return m_assembly_name; } }

        public List<Guid> ActivationDependencies
        {
            get { return m_activation_dep_list; }
        }

        public List<ElementInfo> GetAllElements()
        {
            return m_elements_list;
        }

        public ElementInfo AddElement(string ElementFileName, string ElementXml)
        {
            ElementInfo el_info = new ElementInfo(this);

            el_info.New = true;
            el_info.ID = m_element_counter;

            el_info.EventReceivers = new List<EventReceiverInfo>();
            el_info.EventReceiversInit = new List<EventReceiverInfo>();
            el_info.AttachedEventReceiverClasses = new List<CodeClass>();
            el_info.AttachedEventReceiverClassesInit = new List<CodeClass>();

            m_element_counter++;

            if (string.IsNullOrEmpty(ElementFileName))
            {
                if (m_element_files_list.Count > 0)
                {
                    string[] arr = new string[m_element_files_list.Count];
                    m_element_files_list.Keys.CopyTo(arr, 0);
                    ElementFileName = arr[0];
                }
                else
                {
                    ElementFileName = "Elements.xml";
                }
            }

            if (m_element_files_list.ContainsKey(ElementFileName.ToLower()))
            {
                try
                {
                    el_info.ProjectItem = m_feature_folder.ProjectItems.Item(ElementFileName);
                }
                catch { }

                el_info.XmlDoc = m_element_files_list[ElementFileName.ToLower()];
            }
            else
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
<Elements xmlns=""http://schemas.microsoft.com/sharepoint/"">
</Elements>");

                m_element_files_list.Add(ElementFileName.ToLower(), xmldoc);

                el_info.XmlDoc = xmldoc;

                m_elements_init_xml_hash_code.Add(ElementFileName.ToLower(), xmldoc.OuterXml.GetHashCode());

            }


            el_info.ElementFileName = ElementFileName;

            XmlDocument xmldoc_temp = new XmlDocument();
            xmldoc_temp.LoadXml(ElementXml);

            el_info.ElementName = xmldoc_temp.DocumentElement.LocalName;
            el_info.XmlElementNode = el_info.XmlDoc.CreateElement(el_info.ElementName, Common.C_MS_SHAREPOINT_XMLNS);

            foreach (XmlAttribute attrib in xmldoc_temp.DocumentElement.Attributes)
            {
                el_info.XmlElementNode.SetAttribute(attrib.Name, attrib.Value);
            }

            el_info.XmlElementNode.InnerXml = xmldoc_temp.DocumentElement.InnerXml;
            el_info.XmlDoc.DocumentElement.AppendChild(el_info.XmlElementNode);

            el_info.Key = GetElementKey(el_info);

            m_elements_list.Add(el_info);

            return el_info;
        }

        private string GetElementKey(ElementInfo elInfo)
        {
            string key = null;
            if (elInfo.ElementName == "ListTemplate")
            {
                int type;
                try
                {
                    type = int.Parse(Common.GetXmlAttribute(elInfo.XmlElementNode, "Type"));
                    key = "ListTemplate_" + type.ToString();
                }
                catch
                {
                }
            }
            else if (elInfo.ElementName == "ContentType")
            {
                key = "ContentType_" + Common.GetXmlAttribute(elInfo.XmlElementNode, "ID");
            }

            return key;
        }

        public ElementInfo GetListTemplateElementOfType(int Type)
        {
            string s = Type.ToString();

            foreach (ElementInfo info in m_elements_list)
            {
                if (info.ElementName != "ListTemplate")
                    continue;

                if (info.XmlElementNode.GetAttribute("Type") == s)
                {
                    return info;
                }
            }

            return null;
        }

        public void RemoveElement(int ElementID, bool CommitChangesToFile)
        {
            ProjectItem item = null;
            XmlDocument xmldoc = null;

            int idx_to_remove = -1;
            for (int i = 0; i < m_elements_list.Count; i++)
            {
                if (ElementID == m_elements_list[i].ID)
                {
                    item = m_elements_list[i].ProjectItem;
                    xmldoc = m_elements_list[i].XmlDoc;

                    idx_to_remove = i;

                    break;
                }
            }

            if (idx_to_remove != -1)
            {
                XmlElement xel = m_elements_list[idx_to_remove].XmlElementNode;


                if (xel.LocalName == "ContentType" ||
                    xel.LocalName == "ListTemplate")
                {
                    string key;
                    if (xel.LocalName == "ContentType")
                    {
                        key = "ContentType_" + Common.GetXmlAttribute(xel, "ID");
                    }
                    else
                    {
                        string type = Common.GetXmlAttribute(xel, "Type");
                        key = "ListTemplate_" + type;

                        if (!string.IsNullOrEmpty(type))
                            RemoveListEventRegistration(int.Parse(type), CommitChangesToFile);
                    }
                }


                RemoveXMLElementFromParent(xel, false);

                m_elements_list.RemoveAt(idx_to_remove);
            }

            if (CommitChangesToFile && item != null && xmldoc != null)
            {
                //SCC handle
                if (Common.CheckOutItemFromSCC(item))
                {
                    Common.SaveXmlIndented(ref xmldoc, Common.GetProjectItemPath(item));
                }
            }

        }

        public void RemoveFeatureXMLElementFile(string LocationAttribute, bool UseWildcard)
        {
            List<XmlElement> elements_to_remove = new List<XmlElement>();

            foreach (XmlNode node in m_feature_file.GetElementsByTagName("ElementFile"))
            {
                XmlElement el = node as XmlElement;
                if (el == null)
                    continue;

                if (UseWildcard)
                {
                    if (el.GetAttribute("Location").ToLower().StartsWith(LocationAttribute.ToLower()))
                    {
                        if (!elements_to_remove.Contains(el))
                            elements_to_remove.Add(el);
                    }
                }
                else
                {
                    if (el.GetAttribute("Location").ToLower() == LocationAttribute.ToLower())
                    {
                        if (!elements_to_remove.Contains(el))
                            elements_to_remove.Add(el);
                    }
                }
            }

            foreach (XmlElement element in elements_to_remove)
            {
                RemoveXMLElementFromParent(element, true);
            }
        }

        public void RemoveListEventRegistration(int ListType, bool CommitChangesToFile)
        {
            string list_type = ListType.ToString();

            foreach (string file in m_element_files_list.Keys)
            {
                XmlDocument xmldoc = m_element_files_list[file];
                List<XmlNode> nodes_to_remove = new List<XmlNode>();

                foreach (XmlNode node in xmldoc.DocumentElement.ChildNodes)
                {
                    if (node.LocalName == "Receivers")
                    {
                        XmlElement element = node as XmlElement;

                        
                        if (element.GetAttribute("ListTemplateOwner") != "")
                        {
                            Guid g = Guid.Empty;
                            try
                            {
                                g = new Guid(element.GetAttribute("ListTemplateOwner"));
                            }
                            catch
                            {
                            }

                            if (g != Guid.Empty)
                            {
                                if (g != m_feature_id)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                continue;
                            }
                        }
                        

                        if (Common.GetXmlAttribute(element, "ListTemplateId") == list_type)
                        {
                            nodes_to_remove.Add(element);
                        }

                    }
                }


                foreach (XmlNode node in nodes_to_remove)
                {
                    RemoveXMLElementFromParent(node, true);
                }


                if (CommitChangesToFile && nodes_to_remove.Count > 0)
                {
                    //SCC handle
                    ProjectItem item = m_feature_folder.ProjectItems.Item(file);
                    if (Common.CheckOutItemFromSCC(item))
                    {
                        Common.SaveXmlIndented(ref xmldoc, Common.GetProjectItemPath(item));
                    }
                }

            }

        }

        public ElementInfo GetEventReceiversForList(int ListType, bool CreateIfNotExists)
        {
            foreach (ElementInfo info in m_elements_list)
            {
                if (info.ElementName != "Receivers")
                    continue;

                if (info.XmlElementNode.GetAttribute("ListTemplateId") == ListType.ToString())
                    return info;
            }

            if (CreateIfNotExists)
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml("<Receivers ListTemplateId=\"" + ListType.ToString() + "\"/>");

                return AddElement("EventRegistrations.xml", xmldoc.DocumentElement.OuterXml);
            }
            else
            {
                return new ElementInfo(this);
            }
        }

        private bool EventReceiverInfoExists(IList<EventReceiverInfo> EventReceiverList, EventReceiverInfo ReceiverInfoToSearchFor)
        {
            foreach (EventReceiverInfo info in EventReceiverList)
            {
                if (info.AssemblyName == null)
                    continue;

                if (info.AssemblyName.Replace(" ", "") == ReceiverInfoToSearchFor.AssemblyName.Replace(" ", ""))
                {
                    if (info.AssemblyClass == ReceiverInfoToSearchFor.AssemblyClass)
                    {
                        if (ReceiverInfoToSearchFor.EventType == EventReceiverType.Invalid)
                            return true;

                        if (info.EventType == ReceiverInfoToSearchFor.EventType)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        private void Init()
        {
            m_feature_file = new XmlDocument();

            m_elements_list = new List<ElementInfo>();
            m_element_files_list = new Dictionary<string, XmlDocument>();
            m_elements_init_xml_hash_code = new Dictionary<string, int>();

            m_classes = new Dictionary<string, List<CodeClass>>();

            m_element_counter = 0;
            m_feature_id = Guid.Empty;

            try
            {
                if (string.IsNullOrEmpty(m_assembly_name))
                    RefreshAssemblyName();
            }
            catch
            {
                m_assembly_name = string.Empty;
            }

        }

        public void RefreshAssemblyName()
        {
            m_assembly_name = Common.GetTargetBuildAssemblyName(m_feature_folder.ContainingProject, true);
        }

        public ProjectItem GetFeatureXMLFile(bool CreateIfNotExists)
        {
            ProjectItem feature_xml_item = null;
            try
            {
                feature_xml_item = m_feature_folder.ProjectItems.Item("Feature.xml");
            }
            catch
            {
                if (!CreateIfNotExists)
                    return null;

                string temp_file_path = Path.GetTempPath() + "\\Feature.xml";

                if (File.Exists(temp_file_path))
                    File.Delete(temp_file_path);

                try
                {
                    using (StreamWriter writer = File.CreateText(temp_file_path))
                    {
                        writer.Write(
@"<?xml version=""1.0"" encoding=""utf-8""?>
<Feature xmlns=""http://schemas.microsoft.com/sharepoint/"">
</Feature>");
                    }

                    m_feature_folder.ProjectItems.AddFromFileCopy(temp_file_path);

                    feature_xml_item = m_feature_folder.ProjectItems.Item("Feature.xml");
                }
                finally
                {
                    try
                    {
                        File.Delete(temp_file_path);
                    }
                    catch { }
                }
            }

            return feature_xml_item;
        }

        public void RemoveClassesInfoByKey(string Key)
        {
            if (Key == null)
                return;

            if (m_classes.ContainsKey(Key))
                m_classes.Remove(Key);
        }

        public void ReadContent()
        {
            Init();

            //Load feature xml
            ProjectItem feature_xml_item = GetFeatureXMLFile(false);
            if (feature_xml_item == null)
                throw new Exception("Could not find feature.xml file.");

            try
            {
                m_feature_file.Load(Common.GetProjectItemPath(feature_xml_item));
            }
            catch (XmlException ex)
            {
                throw new XmlException("Error loading feature xml file. " + ex.SourceUri + ". " + ex.Message, ex.InnerException, ex.LineNumber, ex.LinePosition);
            }

            this.FeatureID = Common.GetXmlAttribute(m_feature_file.DocumentElement, "ID");
            this.FeatureTitle = Common.GetXmlAttribute(m_feature_file.DocumentElement, "Title");
            this.FeatureDescription = Common.GetXmlAttribute(m_feature_file.DocumentElement, "Description");
            this.FeatureVersion = Common.GetXmlAttribute(m_feature_file.DocumentElement, "Version");
            this.FeatureScope = Common.GetXmlAttribute(m_feature_file.DocumentElement, "Scope");
            this.FeatureDefaultResourceFile = Common.GetXmlAttribute(m_feature_file.DocumentElement, "DefaultResourceFile");

            try
            {
                m_feature_id = new Guid(this.FeatureID);
            }
            catch
            {
            }

            string s = Common.GetXmlAttribute(m_feature_file.DocumentElement, "Hidden");
            if (!string.IsNullOrEmpty(s))
                this.FeatureHidden = bool.Parse(s);

            this.FeatureEventReceiverAssembly = Common.GetXmlAttribute(m_feature_file.DocumentElement, "ReceiverAssembly");
            this.FeatureEventReceiverClass = Common.GetXmlAttribute(m_feature_file.DocumentElement, "ReceiverClass");


            LoadFeatureMetaInfo();


            //Process all element files.
            foreach (ProjectItem item in m_feature_folder.ProjectItems)
            {
                if (item.Kind != Constants.vsProjectItemKindPhysicalFile)
                    continue;

                if (Path.GetExtension(item.Name).ToLower() != ".xml")
                    continue;

                XmlDocument xmldoc = new XmlDocument();

                try
                {
                    xmldoc.Load(Common.GetProjectItemPath(item));
                }
                catch(XmlException ex)
                {
                    throw new XmlException("Error loading xml " + ex.SourceUri + ". " + ex.Message, ex.InnerException, ex.LineNumber, ex.LinePosition);
                }

                if (xmldoc.DocumentElement.LocalName != "Elements")
                    continue;


                foreach (XmlNode node in xmldoc.DocumentElement.ChildNodes)
                {
                    if (node.NodeType == XmlNodeType.Element)
                    {
                        XmlElement element = node as XmlElement;

                        ElementInfo el_info = new ElementInfo(this);
                        el_info.ID = m_element_counter;
                        el_info.ProjectItem = item;
                        el_info.XmlDoc = element.OwnerDocument;
                        el_info.XmlElementNode = element;
                        el_info.ElementName = element.LocalName;
                        el_info.ElementFileName = item.Name;
                        el_info.EventReceivers = new List<EventReceiverInfo>();
                        el_info.EventReceiversInit = new List<EventReceiverInfo>();

                        el_info.Key = GetElementKey(el_info);

                        if (el_info.Key != null)
                        {
                            if (m_classes.ContainsKey(el_info.Key))
                                el_info.AttachedEventReceiverClasses = m_classes[el_info.Key];
                            else
                                el_info.AttachedEventReceiverClasses = new List<CodeClass>();
                        }
                        else
                        {
                            el_info.AttachedEventReceiverClasses = new List<CodeClass>();
                        }
                        el_info.AttachedEventReceiverClassesInit = new List<CodeClass>();

                        m_elements_list.Add(el_info);
                        m_element_counter++;
                    }
                }

                m_element_files_list.Add(item.Name.ToLower(), xmldoc);
                m_elements_init_xml_hash_code.Add(item.Name.ToLower(), xmldoc.OuterXml.GetHashCode());
            }


            //Process event receiver registrations
            ReadAndProcessEventRegistrations();

            /*Refresh attached classes*/
            GenerateEventReceivers();

  
            XmlNamespaceManager manager = new XmlNamespaceManager(m_feature_file.NameTable);
            manager.AddNamespace("sp", Common.C_MS_SHAREPOINT_XMLNS);


            m_activation_dep_list = new List<Guid>();
            foreach(XmlNode node in m_feature_file.GetElementsByTagName("ActivationDependency"))
            {
                XmlElement xel = node as XmlElement;
                if (xel == null)
                    continue;

                Guid id;
                try
                {
                    id = new Guid(Common.GetXmlAttribute(xel, "FeatureId").ToUpper());
                }
                catch
                {
                    id = Guid.Empty;
                }

                m_activation_dep_list.Add(id);
            }



            m_feature_file_init_xml_hash_code = m_feature_file.OuterXml.GetHashCode();


        }

        public void LoadFeatureMetaInfo()
        {
            ProjectItem featuresMetaInfo = null;
            try
            {
                featuresMetaInfo = m_feature_folder.ProjectItems.Item(Common.C_FEATURE_META_INFO_FILE_NAME);
            }
            catch { }

            if (featuresMetaInfo == null)
                return;


            string filePath = Common.GetProjectItemPath(featuresMetaInfo, false);
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.PreserveWhitespace = true;
            xmldoc.Load(filePath);

            m_classes_init_hash = xmldoc.OuterXml.GetHashCode();

            this.FeatureDefaultCodeFolder = Common.GetXmlAttribute(xmldoc.DocumentElement, "DefaultCodeFolder");
            this.FeatureDefaultCodeNamespace = Common.GetXmlAttribute(xmldoc.DocumentElement, "DefaultCodeNamespace");

            m_classes = new Dictionary<string, List<CodeClass>>();

            XmlNodeList nodeList = xmldoc.SelectNodes("/MetaInfo/*");
            foreach (XmlElement el in nodeList)
            {
                List<CodeClass> list = new List<CodeClass>();

                foreach (XmlElement elClass in el.GetElementsByTagName("Class"))
                {
                    CodeType t = m_special_project.Project.CodeModel.CodeTypeFromFullName(elClass.InnerText);
                    if (t != null)
                    {
                        list.Add(t as CodeClass);

                        m_has_classes = true;
                    }
                }

                m_classes.Add(el.GetAttribute("Name"), list);
            }
        }

        private void ReadAndProcessEventRegistrations()
        {
            for (int i = 0; i < m_elements_list.Count; i++)
            {
                if (m_elements_list[i].ElementName != "Receivers" && m_elements_list[i].ElementName != "ContentType")
                {
                    continue;
                }

                string key;
                ElementInfo evt_receiver_owner_element;

                if (m_elements_list[i].ElementName == "Receivers")
                {
                    int type = 0;
                    try
                    {
                        type = int.Parse(m_elements_list[i].XmlElementNode.GetAttribute("ListTemplateId"));
                    }
                    catch
                    {
                        //continue;
                    }

                    evt_receiver_owner_element = GetListTemplateElementOfType(type);
                    if (evt_receiver_owner_element == null)
                        continue;

                    key = "ListTemplate_" + type.ToString();
                }
                else
                {
                    key = "ContentType_" + Common.GetXmlAttribute(m_elements_list[i].XmlElementNode, "ID");
                    evt_receiver_owner_element = m_elements_list[i];
                }



                foreach (XmlNode xnode in m_elements_list[i].XmlElementNode.GetElementsByTagName("Receiver"))
                {
                    XmlElement tmp;
                    EventReceiverInfo evt_rec_info = new EventReceiverInfo();

                    evt_rec_info.ReceiverRegistrationElement = xnode as XmlElement;

                    tmp = Common.GetXmlChildNodeByName(xnode, "Assembly");
                    if (tmp != null)
                        evt_rec_info.AssemblyName = tmp.InnerText;

                    tmp = Common.GetXmlChildNodeByName(xnode, "Class");
                    if (tmp != null)
                        evt_rec_info.AssemblyClass = tmp.InnerText;

                    tmp = Common.GetXmlChildNodeByName(xnode, "Type");
                    if (tmp != null)
                    {
                        try
                        {
                            evt_rec_info.EventType = (EventReceiverType)Enum.Parse(typeof(EventReceiverType), tmp.InnerText);
                        }
                        catch { }
                    }

                    
                    if (Common.CompareAssemblyName(evt_rec_info.AssemblyName, m_assembly_name))
                    {
                        if (m_classes.ContainsKey(key))
                        {
                            CodeClass class_to_find = m_classes[key].Find(cls => cls.FullName == evt_rec_info.AssemblyClass);

                            if (class_to_find != null)
                            {
                                evt_rec_info.IsGeneratedFromCodeFile = true;
                                evt_rec_info.ParentCodeClass = class_to_find;
                            }
                        }
                    }
                    else
                    {
                        evt_rec_info.IsExternal = true;
                    }

                    evt_receiver_owner_element.EventReceivers.Add(evt_rec_info);
                }

                if (evt_receiver_owner_element.EventReceivers != null)
                {
                    evt_receiver_owner_element.EventReceiversInit = new List<EventReceiverInfo>(evt_receiver_owner_element.EventReceivers);
                }
            }
        }

        public void WriteContent(bool ForceUpdate)
        {
            List<string> files_to_add = new List<string>();
            string skip_files = m_special_project.GetUserSettingsValue("SkipFilesPushDown");


            //Precess event registration info
            GenerateEventReceivers();



            //Process all elements
            for (int i = 0; i < m_elements_list.Count; i++ )
            {
                ElementInfo el_info = m_elements_list[i];

                XmlNamespaceManager manager = new XmlNamespaceManager(el_info.XmlDoc.NameTable);
                manager.AddNamespace("sp", Common.C_MS_SHAREPOINT_XMLNS);

                if (el_info.ProjectItem == null)
                {
                    string file_name = el_info.ElementFileName;

                    try
                    {
                        el_info.ProjectItem = m_feature_folder.ProjectItems.Item(file_name);
                    }
                    catch { }

                    if (el_info.ProjectItem == null)
                    {
                        if (File.Exists(Common.GetProjectItemPath(m_feature_folder) + "\\" + file_name))
                        {
                            throw new Exception("File '" + file_name + "' already exists at '" + Common.GetProjectItemPath(m_feature_folder) + "'.");
                        }

                        string temp_file_path = Path.GetTempPath() + "\\" + file_name;

                        if (File.Exists(temp_file_path))
                            File.Delete(temp_file_path);

                        try
                        {
                            using (StreamWriter writer = File.CreateText(temp_file_path))
                            {
                                writer.Write(
    @"<?xml version=""1.0"" encoding=""utf-8""?>
<Elements xmlns=""http://schemas.microsoft.com/sharepoint/"">
</Elements>");
                            }

                            m_feature_folder.ProjectItems.AddFromFileCopy(temp_file_path);

                            el_info.ProjectItem = m_feature_folder.ProjectItems.Item(file_name);
                        }
                        finally
                        {
                            try
                            {
                                File.Delete(temp_file_path);
                            }
                            catch { }
                        }
                    }

                    if (!m_element_files_list.ContainsKey(file_name.ToLower()))
                    {
                        XmlDocument xmldoc = new XmlDocument();
                        xmldoc.Load(Common.GetProjectItemPath(el_info.ProjectItem));
                        m_element_files_list.Add(file_name.ToLower(), xmldoc);
                    }
                }

                if (el_info.ElementName == "Module")
                {
                    ProjectItem module_folder = null;
                    try
                    {
                        module_folder = m_feature_folder.ProjectItems.Item(el_info.XmlElementNode.GetAttribute("Path"));
                    }
                    catch { }

                    if (module_folder != null)
                    {
                        foreach (ProjectItem item in module_folder.ProjectItems)
                        {
                            if (Common.ShouldIgnoreFile(item.Name, skip_files))
                                continue;

                            XmlElement xel = el_info.XmlElementNode.SelectSingleNode("../sp:Module[@Path='" + module_folder.Name + "']/sp:File[@Url='" + item.Name + "']", manager) as XmlElement;
                            if (xel == null)
                            {
                                xel = el_info.XmlDoc.CreateElement("File", Common.C_MS_SHAREPOINT_XMLNS);
                                xel.SetAttribute("Url", item.Name);
                                xel.SetAttribute("Type", "GhostableInLibrary");
                                xel.SetAttribute("IgnoreIfAlreadyExists", "FALSE");
                                el_info.XmlElementNode.AppendChild(xel);

                                AddFeatureElementFile(module_folder.Name + "/" + item.Name);
                            }

                        }
                    }

                }

                else if (el_info.ElementName == "ListTemplate")
                {
                    ProjectItem list_template_folder = null;
                    try
                    {
                        list_template_folder = m_feature_folder.ProjectItems.Item(el_info.XmlElementNode.GetAttribute("Name"));
                    }
                    catch { }

                    if (list_template_folder != null)
                    {
                        foreach (ProjectItem item in list_template_folder.ProjectItems)
                        {
                            if (Common.ShouldIgnoreFile(item.Name, skip_files))
                                continue;

                            AddFeatureElementFile(list_template_folder.Name + "\\" + item.Name);
                        }
                    }
                }

            }



            foreach (KeyValuePair<string, XmlDocument> kvp in m_element_files_list)
            {
                ProjectItem item = null;
                try
                {
                    item = m_feature_folder.ProjectItems.Item(kvp.Key);
                }
                catch
                {
                    continue;
                }

                AddFeatureElementManifest(item.Name);

                XmlDocument xmldoc = kvp.Value;
                if (!ForceUpdate)
                {
                    if (xmldoc.OuterXml.GetHashCode() == m_elements_init_xml_hash_code[kvp.Key])
                        continue;
                }

                //SCC handle
                if (!Common.CheckOutItemFromSCC(item))
                    return;

                Common.SaveXmlIndented(ref xmldoc, Common.GetProjectItemPath(item));
            }


            //Feature file.

            Common.SetXmlAttribute(m_feature_file.DocumentElement, "Id", this.FeatureID, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "Title", this.FeatureTitle, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "Description", this.FeatureDescription, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "Version", this.FeatureVersion, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "Scope", this.FeatureScope);
            Common.SetXmlAttributeIgnoreIfValueMatches(m_feature_file.DocumentElement, "Hidden", this.FeatureHidden.ToString(), true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "ReceiverAssembly", this.FeatureEventReceiverAssembly, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "ReceiverClass", this.FeatureEventReceiverClass, true);
            Common.SetXmlAttribute(m_feature_file.DocumentElement, "DefaultResourceFile", this.FeatureDefaultResourceFile, true);

            if (string.IsNullOrEmpty(this.FeatureEventReceiverAssembly))
            {
                m_feature_file.DocumentElement.RemoveAttribute("ReceiverAssembly");
            }
            if (string.IsNullOrEmpty(this.FeatureEventReceiverClass))
            {
                m_feature_file.DocumentElement.RemoveAttribute("ReceiverClass");
            }

            ProjectItem resources_folder = null;
            try
            {
                resources_folder = m_feature_folder.ProjectItems.Item("Resources");
            }
            catch { }

            if (resources_folder != null)
            {
                foreach (ProjectItem item in resources_folder.ProjectItems)
                {
                    if (Common.ShouldIgnoreFile(item.Name, skip_files))
                        continue;

                    AddFeatureElementFile(resources_folder.Name + "\\" + item.Name);
                }
            }


            RefreshActivationDependencies();


            if (ForceUpdate || (m_feature_file_init_xml_hash_code != m_feature_file.OuterXml.GetHashCode()))
            {
                CommitChangesToFeatureXML();
            }


            //Features meta info
            SaveFeatureMetaInfo();
        }

        public void SaveFeatureMetaInfo()
        {
            string filePath = Path.GetTempPath();
            if (!filePath.EndsWith("\\"))
                filePath += "\\";

            filePath += Common.C_FEATURE_META_INFO_FILE_NAME;

            if (File.Exists(filePath))
                File.Delete(filePath);


            XmlDocument xmldoc = new XmlDocument();

            XmlComment comment = xmldoc.CreateComment(Common.C_FEATURE_META_INFO_COMMENT);
            xmldoc.AppendChild(comment);

            XmlElement root = xmldoc.CreateElement("MetaInfo");
            xmldoc.AppendChild(root);

            Common.SetXmlAttribute(xmldoc.DocumentElement, "DefaultCodeFolder", this.FeatureDefaultCodeFolder, true);
            Common.SetXmlAttribute(xmldoc.DocumentElement, "DefaultCodeNamespace", this.FeatureDefaultCodeNamespace, true);

            bool needsPersist = false;
            foreach (KeyValuePair<string, List<CodeClass>> kvp in m_classes)
            {
                List<CodeClass> classes = kvp.Value;
                
                if (classes.Count == 0)
                    continue;


                XmlElement elements = xmldoc.CreateElement("Element");
                elements.SetAttribute("Name", kvp.Key);
                root.AppendChild(elements);

                foreach (CodeClass cls in classes)
                {
                    XmlElement elClass = xmldoc.CreateElement("Class");
                    elClass.InnerText = cls.FullName;
                    elements.AppendChild(elClass);

                    needsPersist = true;
                }
            }

            if (!m_has_classes)
            {
                if (string.IsNullOrEmpty(this.FeatureDefaultCodeFolder) && !needsPersist)
                    return;
            }

            try
            {
                Common.SaveXmlIndented(ref xmldoc, filePath);

                xmldoc = new XmlDocument();
                xmldoc.PreserveWhitespace = true;
                xmldoc.Load(filePath);

                int newHash = xmldoc.OuterXml.GetHashCode();

                if (newHash == m_classes_init_hash)
                    return;


                ProjectItem featuresMetaInfo = null;
                try
                {
                    featuresMetaInfo = m_feature_folder.ProjectItems.Item(Common.C_FEATURE_META_INFO_FILE_NAME);
                }
                catch
                {
                }

                if (featuresMetaInfo != null)
                {
                    bool b = Common.CheckOutItemFromSCC(featuresMetaInfo);
                    if (!b)
                        return;

                    Common.SaveXmlIndented(ref xmldoc, Common.GetProjectItemPath(featuresMetaInfo, false));
                }
                else
                {
                    m_feature_folder.ProjectItems.AddFromFileCopy(filePath);
                }

                m_classes_init_hash = newHash;
            }
            finally
            {
                if (File.Exists(filePath))
                    File.Delete(filePath);
            }

        }

        public void CommitChangesToFeatureXML()
        {
            //SCC handle
            ProjectItem feature_xml_item = m_feature_folder.ProjectItems.Item("Feature.xml");
            if (!Common.CheckOutItemFromSCC(feature_xml_item))
                return;

            Common.SaveXmlIndented(ref m_feature_file, Common.GetProjectItemPath(feature_xml_item));
        }

        private void RefreshActivationDependencies()
        {
            XmlNamespaceManager manager = new XmlNamespaceManager(m_feature_file.NameTable);
            manager.AddNamespace("sp", Common.C_MS_SHAREPOINT_XMLNS);

            List<XmlElement> elements_to_remove = new List<XmlElement>();

            foreach (XmlNode node in m_feature_file.SelectNodes("/sp:Feature/sp:ActivationDependencies/sp:ActivationDependency", manager))
            {
                XmlElement xel = node as XmlElement;
                if (xel == null)
                    continue;

                try
                {
                    Guid id = new Guid(Common.GetXmlAttribute(xel, "FeatureId").ToUpper());
                    if (!m_activation_dep_list.Contains(id))
                    {
                        elements_to_remove.Add(xel);
                    }
                }
                catch { }
            }

            foreach (XmlElement xel in elements_to_remove)
            {
                RemoveXMLElementFromParent(xel, true);
            }

            foreach (Guid activation_id in m_activation_dep_list)
            {
                bool found = false;

                foreach (XmlNode node in m_feature_file.SelectNodes("/sp:Feature/sp:ActivationDependencies/sp:ActivationDependency", manager))
                {
                    XmlElement xel = node as XmlElement;
                    if (xel == null)
                        continue;

                    try
                    {
                        Guid id = new Guid(Common.GetXmlAttribute(xel, "FeatureId").ToUpper());
                        if (id == activation_id)
                        {
                            found = true;
                            break;
                        }
                    }
                    catch { }
                }

                if (!found)
                {
                    XmlElement el_act_dep_root = m_feature_file.SelectSingleNode("/sp:Feature/sp:ActivationDependencies", manager) as XmlElement;
                    if (el_act_dep_root == null)
                    {
                        el_act_dep_root = m_feature_file.CreateElement("ActivationDependencies", Common.C_MS_SHAREPOINT_XMLNS);
                        m_feature_file.DocumentElement.AppendChild(el_act_dep_root);
                    }

                    XmlElement el_act_dep = m_feature_file.CreateElement("ActivationDependency", Common.C_MS_SHAREPOINT_XMLNS);
                    el_act_dep.SetAttribute("FeatureId", activation_id.ToString("D").ToUpper());

                    el_act_dep_root.AppendChild(el_act_dep);
                }

            }

        }

        private void AddFeatureElementFile(string Location)
        {
            XmlNamespaceManager manager = new XmlNamespaceManager(m_feature_file.NameTable);
            manager.AddNamespace("sp", Common.C_MS_SHAREPOINT_XMLNS);

            XmlNode element_manifests_node = m_feature_file.SelectSingleNode("/sp:Feature/sp:ElementManifests",manager);
            if (element_manifests_node == null)
            {
                element_manifests_node = m_feature_file.CreateElement("ElementManifests", Common.C_MS_SHAREPOINT_XMLNS);
                m_feature_file.DocumentElement.AppendChild(element_manifests_node);
            }

            bool found = false;
            foreach (XmlNode node in element_manifests_node.ChildNodes)
            {
                XmlElement element = node as XmlElement;
                if (element == null)
                    continue;

                if (Common.GetXmlAttribute(element, "Location").ToLower() == Location.ToLower())
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                XmlElement xel = m_feature_file.CreateElement("ElementFile", Common.C_MS_SHAREPOINT_XMLNS);
                xel.SetAttribute("Location", Location);
                element_manifests_node.AppendChild(xel);
            }
        }

        private void AddFeatureElementManifest(string ElementManifestName)
        {
            XmlNamespaceManager manager = new XmlNamespaceManager(m_feature_file.NameTable);
            manager.AddNamespace("sp", Common.C_MS_SHAREPOINT_XMLNS);

            XmlNode element_manifests_node = m_feature_file.SelectSingleNode("/sp:Feature/sp:ElementManifests", manager);
            if (element_manifests_node == null)
            {
                element_manifests_node = m_feature_file.CreateElement("ElementManifests", Common.C_MS_SHAREPOINT_XMLNS);
                m_feature_file.DocumentElement.AppendChild(element_manifests_node);
            }

            bool found = false;
            foreach (XmlNode node in element_manifests_node.ChildNodes)
            {
                XmlElement element = node as XmlElement;
                if (element == null)
                    continue;

                if (Common.GetXmlAttribute(element, "Location").ToLower() == ElementManifestName.ToLower())
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                XmlElement xel = m_feature_file.CreateElement("ElementManifest", Common.C_MS_SHAREPOINT_XMLNS);
                xel.SetAttribute("Location", ElementManifestName);
                element_manifests_node.AppendChild(xel);
            }

        }

        private void RemoveXMLElementFromParent(XmlNode element, bool RemoveParentIfEmpty)
        {
            if (element == null)
                return;

            XmlNode parent = element.ParentNode;
            if (parent == null)
                return;

            parent.RemoveChild(element);

            if (RemoveParentIfEmpty && parent.ChildNodes.Count == 0)
            {
                XmlNode parent2 = parent.ParentNode;
                if (parent2 != null)
                {
                    if (parent.LocalName == "Receivers")
                    {
                        //For list templates
                        string type = Common.GetXmlAttribute(parent as XmlElement, "ListTemplateId");
                        if (!string.IsNullOrEmpty(type))
                        {
                            ElementInfo elInfo = GetEventReceiversForList(int.Parse(type), false);
                            if (elInfo != null)
                            {
                                RemoveElement(elInfo.ID, false);
                            }
                        }
                        else
                        {
                            //Content types
                            if (parent2.LocalName == "XmlDocument")
                            {
                                parent2.RemoveChild(parent);

                                if (parent2.ChildNodes.Count == 0)
                                {
                                    XmlNode parent3 = parent2.ParentNode;
                                    parent3.RemoveChild(parent2);

                                    if (parent3.ChildNodes.Count == 0)
                                    {
                                        parent3.ParentNode.RemoveChild(parent3);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        parent2.RemoveChild(parent);
                    }
                }
            }
        }

        public void GenerateEventReceivers()
        {
            //Check for event receivers in code files.
            string key = null;

            try
            {
                RefreshAssemblyName();
            }
            catch (Exception ex)
            {
                return;
                //throw new Exception("Could not read output build assembly name. Check if the project has a valid output build. " + ex.Message);
            }

            if (string.IsNullOrEmpty(m_assembly_name))
                return;

            if (!string.IsNullOrEmpty(this.FeatureEventReceiverClass))
            {
                CodeType t = m_special_project.Project.CodeModel.CodeTypeFromFullName(this.FeatureEventReceiverClass);
                if (t != null && t.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject)
                {
                    this.FeatureEventReceiverAssembly = m_assembly_name;
                }
            }


            for (int i = 0; i < m_elements_list.Count; i++)
            {
                ElementInfo el_info = m_elements_list[i];

                key = el_info.Key;

                if (key == null)
                    continue;


                if (!m_classes.ContainsKey(key))
                {
                    m_classes.Add(key, null);
                }
                m_classes[key] = el_info.AttachedEventReceiverClasses;


                foreach (CodeClass codeClass in el_info.AttachedEventReceiverClassesInit)
                {
                    bool bKeep = el_info.AttachedEventReceiverClasses.Exists(c => c == codeClass);
                    if (!bKeep)
                    {
                        el_info.EventReceivers.RemoveAll(evtInfo => evtInfo.ParentCodeClass == codeClass);
                    }
                }

                ProcessCodeFiles(key, el_info.XmlElementNode, el_info.AttachedEventReceiverClasses as IList<CodeClass>, el_info.EventReceivers as List<EventReceiverInfo>);


                foreach (EventReceiverInfo evtInfo in el_info.EventReceiversInit)
                {
                    if (evtInfo.ReceiverRegistrationElement == null)
                        continue;

                    bool bKeep = el_info.EventReceivers.Exists(evtInfo2 => evtInfo2 == evtInfo);
                    if (bKeep && evtInfo.IsGeneratedFromCodeFile && Common.CompareAssemblyName(evtInfo.AssemblyName, m_assembly_name))
                    {
                        if (!m_classes.ContainsKey(key))
                        {
                            bKeep = false;
                        }
                        else
                        {
                            if (!m_classes[key].Exists(cls => cls.FullName == evtInfo.AssemblyClass))
                            {
                                bKeep = false;
                            }
                        }
                    }

                    if (!bKeep && evtInfo.ReceiverRegistrationElement != null)
                    {
                        RemoveXMLElementFromParent(evtInfo.ReceiverRegistrationElement, true);
                    }
                }


                el_info.EventReceiversInit = new List<EventReceiverInfo>(el_info.EventReceivers);
                el_info.AttachedEventReceiverClassesInit = new List<CodeClass>(el_info.AttachedEventReceiverClasses);


                if (el_info.ElementName == "ListTemplate")
                {
                    if (el_info.EventReceivers.Count > 0)
                    {
                        int type = int.Parse(Common.GetXmlAttribute(el_info.XmlElementNode, "Type"));
                        ElementInfo receivers = GetEventReceiversForList(type, true);

                        foreach (EventReceiverInfo info in el_info.EventReceivers)
                        {
                            XmlElement element;
                            if (info.ReceiverRegistrationElement == null)
                            {
                                element = receivers.XmlDoc.CreateElement("Receiver", Common.C_MS_SHAREPOINT_XMLNS);

                                element.AppendChild(receivers.XmlDoc.CreateElement("Name", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyClass;
                                element.AppendChild(receivers.XmlDoc.CreateElement("Assembly", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyName;
                                element.AppendChild(receivers.XmlDoc.CreateElement("Class", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyClass;
                                element.AppendChild(receivers.XmlDoc.CreateElement("Type", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.EventType.ToString();

                                receivers.XmlElementNode.AppendChild(element);
                                info.ReceiverRegistrationElement = element;
                            }
                            else
                            {
                                element = info.ReceiverRegistrationElement;

                                try
                                {
                                    if (string.IsNullOrEmpty(element.GetElementsByTagName("Name")[0].InnerText))
                                        element.GetElementsByTagName("Name")[0].InnerText = info.AssemblyClass;

                                    element.GetElementsByTagName("Assembly")[0].InnerText = info.AssemblyName;
                                    element.GetElementsByTagName("Class")[0].InnerText = info.AssemblyClass;
                                    element.GetElementsByTagName("Type")[0].InnerText = info.EventType.ToString();
                                }
                                catch { }
                            }
                        }
                    }
                }
                else if (el_info.ElementName == "ContentType")
                {
                    if (el_info.EventReceivers.Count > 0)
                    {
                        XmlElement tmp;
                        if (el_info.XmlElementNode.GetElementsByTagName("XmlDocuments").Count == 0)
                        {
                            tmp = el_info.XmlElementNode.AppendChild(el_info.XmlDoc.CreateElement("XmlDocuments", Common.C_MS_SHAREPOINT_XMLNS)) as XmlElement;
                        }
                        else
                        {
                            tmp = el_info.XmlElementNode.GetElementsByTagName("XmlDocuments")[0] as XmlElement;
                        }

                        if (tmp.GetElementsByTagName("XmlDocument").Count == 0)
                        {
                            tmp = tmp.AppendChild(el_info.XmlDoc.CreateElement("XmlDocument", Common.C_MS_SHAREPOINT_XMLNS)) as XmlElement;
                            tmp.SetAttribute("NamespaceURI", Common.C_MS_SHAREPOINT_EVENTS_NS);
                        }
                        else
                        {
                            tmp = tmp.GetElementsByTagName("XmlDocument")[0] as XmlElement;
                        }

                        if (tmp.GetElementsByTagName("Receivers").Count == 0)
                        {
                            tmp = tmp.AppendChild(el_info.XmlDoc.CreateElement("Receivers", Common.C_MS_SHAREPOINT_XMLNS)) as XmlElement;
                        }
                        else
                        {
                            tmp = tmp.GetElementsByTagName("Receivers")[0] as XmlElement;
                        }

                        foreach (EventReceiverInfo info in el_info.EventReceivers)
                        {
                            XmlElement element;
                            if (info.ReceiverRegistrationElement == null)
                            {
                                element = tmp.OwnerDocument.CreateElement("Receiver", Common.C_MS_SHAREPOINT_XMLNS);

                                element.AppendChild(tmp.OwnerDocument.CreateElement("Name", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyClass;
                                element.AppendChild(tmp.OwnerDocument.CreateElement("Assembly", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyName;
                                element.AppendChild(tmp.OwnerDocument.CreateElement("Class", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.AssemblyClass;
                                element.AppendChild(tmp.OwnerDocument.CreateElement("Type", Common.C_MS_SHAREPOINT_XMLNS)).InnerText = info.EventType.ToString();

                                tmp.AppendChild(element);

                                info.ReceiverRegistrationElement = element;
                            }
                            else
                            {
                                element = info.ReceiverRegistrationElement;

                                try
                                {
                                    if (string.IsNullOrEmpty(element.GetElementsByTagName("Name")[0].InnerText))
                                        element.GetElementsByTagName("Name")[0].InnerText = info.AssemblyClass;
    
                                    element.GetElementsByTagName("Assembly")[0].InnerText = info.AssemblyName;
                                    element.GetElementsByTagName("Class")[0].InnerText = info.AssemblyClass;
                                    element.GetElementsByTagName("Type")[0].InnerText = info.EventType.ToString();
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
        }

        private void ProcessCodeFiles(string Key, XmlElement Element, IList<CodeClass> Classes, List<EventReceiverInfo> EventReceivers)
        {
            foreach (CodeClass cls in Classes)
            {                
                string NameSpace;
                string ClassName;
                string BaseType;

                if (cls.InfoLocation != vsCMInfoLocation.vsCMInfoLocationProject)
                    continue;

                List<EventReceiverInfo> evtList = ExtractEventReceiverInfoFromCodeFile(cls, out NameSpace, out ClassName, out BaseType);

                EventReceivers.RemoveAll(delegate(EventReceiverInfo e)
                {
                    if (e.ParentCodeClass == cls)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                });


                foreach (EventReceiverInfo evtInfo in evtList)
                {
                    bool found = EventReceivers.Exists(e => Common.CompareAssemblyName(e.AssemblyName, evtInfo.AssemblyName) && e.AssemblyClass == evtInfo.AssemblyClass && e.EventType == evtInfo.EventType );
                    if (!found)
                    {
                        EventReceivers.Add(evtInfo);
                    }
                }
            }
        }

        public List<EventReceiverInfo> ExtractEventReceiverInfoFromCodeFile(CodeClass codeClass, out string NameSpace, out string ClassName, out string BaseType)
        {
            NameSpace = string.Empty;
            ClassName = string.Empty;
            BaseType = string.Empty;

            List<EventReceiverInfo> ret = new List<EventReceiverInfo>();

            //Lists
            CodeElement e = null;
            try
            {
                e = codeClass.Bases.Item("SPItemEventReceiver");
            }
            catch { }

            if (e == null)
            {
                try
                {
                    e = codeClass.Bases.Item("SPListEventReceiver");
                }
                catch { }
            }

            if (e != null)
            {
                BaseType = e.Name;
                NameSpace = codeClass.Namespace.FullName;
                ClassName = codeClass.Name;

                foreach (CodeElement mem in codeClass.Members)
                {
                    if (mem.Kind == vsCMElement.vsCMElementFunction)
                    {
                        CodeFunction2 function = mem as CodeFunction2;

                        EventReceiverType event_typ;
                        try
                        {
                            event_typ = (EventReceiverType)Enum.Parse(typeof(EventReceiverType), mem.Name);
                        }
                        catch
                        {
                            continue;
                        }

                        EventReceiverInfo info = new EventReceiverInfo();
                        info.AssemblyName = m_assembly_name;
                        info.AssemblyClass = codeClass.FullName;
                        info.IsExternal = false;
                        info.EventType = event_typ;
                        info.IsGeneratedFromCodeFile = true;
                        info.ParentCodeClass = codeClass;
                        ret.Add(info);
                    }
                }
            }

            return ret;
        }
    }

    internal class ElementInfo
    {
        public ElementInfo(FeatureManager Manager)
        {
            this.Manager = Manager;
        }

        public int ID { get; set; }
        public string Key { get; set; }
        public FeatureManager Manager { get; private set; }
        public ProjectItem ProjectItem { get; set; }
        public List<CodeClass> AttachedEventReceiverClasses { get; set; }
        public List<CodeClass> AttachedEventReceiverClassesInit { get; set; }
        public string ElementFileName { get; set; }
        public string ElementName { get; set; }
        public List<EventReceiverInfo> EventReceivers
        {
            get;
            set;
        }
        public List<EventReceiverInfo> EventReceiversInit
        {
            get;
            set;
        }
        public XmlDocument XmlDoc { get; set; }
        public XmlElement XmlElementNode { get; set; }
        public bool New { get; set; }
        public string NewElementFileName { get; set; }
    }

    internal class EventReceiverInfo
    {
        [CategoryAttribute("Event registration"), DisplayName("Event type"), ReadOnly(false)]
        public EventReceiverType EventType { get; set; }

        [Browsable(true), ReadOnly(true), DisplayName("External assembly"), Description("The event receiver is in an external assembly.")]
        public bool IsExternal
        {
            get;
            set;
        }

        [Browsable(true), ReadOnly(true), DisplayName("Auto generated"), Description("Auto generated from code file.")]
        public bool IsGeneratedFromCodeFile
        {
            get;
            set;
        }

        [Browsable(false)]
        public XmlElement ReceiverRegistrationElement
        {
            get;
            set;
        }

        [Browsable(false)]
        public CodeClass ParentCodeClass
        {
            get;
            set;
        }

        [Browsable(false)]
        public string UniqueString
        {
            get
            {
                return this.EventType.ToString() + " - " + this.AssemblyClass + ", " + this.AssemblyName;
            }
        }


        [CategoryAttribute("Event registration"), DisplayName("Assembly full name"), ReadOnly(false)]
        public string AssemblyName { get; set; }

        [CategoryAttribute("Event registration"), DisplayName("Class full name"), ReadOnly(false)]
        public string AssemblyClass { get; set; }

        public override string ToString()
        {
            return this.EventType.ToString() + " - " + this.AssemblyClass + ", " + this.AssemblyName;

            /*
            if (this.IsExternal)
                return this.EventType.ToString() + " - External: " + this.AssemblyClass + ", " + this.AssemblyName;
            else
                return this.EventType.ToString() + " - " + this.AssemblyClass;
             */
        }
    }
}
